package com.share.finance.risk.core.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.TypeReference;
import com.share.common.common.Result;
import com.share.common.enums.ErrMsgEnum;
import com.share.common.enums.EventTypeEnum;
import com.share.common.utils.HttpUtil;
import com.share.common.utils.ThreadUtil;
import com.share.finance.risk.common.model.constant.SysConf;
import com.share.finance.risk.common.model.sys.*;
import com.share.finance.risk.common.model.vo.BaseCustomerInfo;
import com.share.finance.risk.core.service.CreditLoanService;
import com.share.finance.risk.core.service.IProductVariateService;
import com.share.finance.risk.core.service.IResultInfoService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Slf4j
@Service
public class CreditLoanServiceImpl implements CreditLoanService {
    @Value("${rootUrl.rule}")
    private String ruleRootUrl;

    @Value("${rootUrl.third}")
    private String thirdRootUrl;

    @Value("${rootUrl.local}")
    private String localRootUrl;

    @Value("${rootUrl.asset}")
    private String assetRootUrl;

    @Value("${rootUrl.fund}")
    private String fundRootUrl;

    @Value("${rootUrl.collection}")
    private String collectionRootUrl;

    @Autowired
    private IProductVariateService iProductVariateService;

    @Autowired
    private IResultInfoService resultInfoService;

    @Override
    public void creditLoanApply(String jsonParam) {
        RuleNode ruleResult = null;
        PreRequest req = null;
        long startTime = System.currentTimeMillis();
        try {
            int cycNum = 0;
            req = JSON.parseObject(jsonParam, PreRequest.class);
            String intIds = SysConf.LOCAL_VAR_INT_ID;
            Map<String, Object> varMap = new HashMap<>();
            while (cycNum++ < 10) {
                //1.请求外部接口+本地变量
                Map<String, String> thirdMap = new HashMap<>();
                if (SysConf.LOCAL_VAR_INT_ID.equals(intIds)) {
                    thirdMap = reqeustLocal(req, intIds, cycNum);

                    //把用户信息包含进去
                    thirdMap.put(SysConf.USER_VAR_INT_ID, JSON.toJSONString(req.getData()));
                    intIds = SysConf.LOCAL_VAR_INT_ID + "," + SysConf.USER_VAR_INT_ID;
                } else {
                    thirdMap = reqeustThird(req, intIds, cycNum);
                }

                //2.变量加工
                Map<String, Object> tmpMap = iProductVariateService.process(req.getProductCode(), req.getEventType(), thirdMap, intIds);
                varMap.putAll(tmpMap);

                //3.请求决策引擎
                log.info("本次加工出来的变量sessionId={},cycNum={},varMap={}", req.getSessionId(), cycNum, JSON.toJSONString(varMap));
                ruleResult = reqeustRule(req, varMap, cycNum);
                String haltNode = ruleResult.getIntIds();
                if (!StringUtils.isEmpty(haltNode)) {
                    intIds = haltNode;
                } else {
                    log.info("决策引擎返回结果sessionId={},result={}", req.getSessionId(), ruleResult.getResultType());

                    //通知其他系统
                    final RuleNode ruleResult2 = ruleResult;
                    final PreRequest req2 = req;
                    ThreadUtil.execute(() -> {
                        //1.通知前置
                        reqeustAsset(req2, ruleResult2);


                        //提现事件（用信）--- 通知放款
                        if (EventTypeEnum.TX.getCode().equals(req2.getEventType()) && !StringUtils.isEmpty(ruleResult2.getCreditLimit())) {
                            //2.通知 资金方 放款
                            Integer status = reqeustFund(req2, ruleResult2);
                        }
                    });
                    break;
                }
            }
        } catch (Exception e) {
            log.error("执行异常param={}", jsonParam, e);
        } finally {
            final RuleNode ruleResult1 = ruleResult;
            final PreRequest req1 = req;
            ThreadUtil.execute(() -> resultInfoService.saveReultInfo(req1, ruleResult1, System.currentTimeMillis() - startTime));
        }
    }

    /**
     * 通知
     *
     * @param req
     * @param req
     * @param ruleNode
     * @return
     */
    private Integer reqeustAsset(PreRequest req, RuleNode ruleNode) {
        int res = 0;
        Map<String, String> reData = new HashMap<>();
        String url = assetRootUrl + "/event/saveResult";

        JSONObject param = new JSONObject();
        param.put("sessionId", req.getSessionId());
        param.put("productCode", req.getProductCode());
        param.put("eventType", req.getEventType());
        param.put("creditLimit", ruleNode.getCreditLimit());
        param.put("resultType", ruleNode.getResultType());
        String jsonStr = param.toJSONString();

        try {
            log.info("请求asset接口url={},data={}", url, jsonStr);
            String tmp = HttpUtil.post(url, jsonStr);
            log.info("请求asset,result={}", tmp);
            Result<Map<String, String>> result = JSON.parseObject(tmp, Result.class);
            if (ErrMsgEnum.SUCCESS.getCode().equals(result.getCode())) {
                res = 1;
            }
        } catch (Exception e) {
            log.error("请求asset接口异常url={},reqData={}", url, jsonStr, e);
        }
        return res;
    }

    //通知 资金方 放款
    private Integer reqeustFund(PreRequest req, RuleNode ruleNode) {
        ruleNode.getCreditLimit();
        int res = 0;
        Map<String, String> reData = new HashMap<>();
        String url = fundRootUrl + "/loan/apply";

        Object objData = req.getData();
        JSONObject userInfo = JSON.parseObject(objData.toString());

        JSONObject param = new JSONObject();
        param.put("idCard", userInfo.getString("idCard"));
        param.put("name", userInfo.getString("name"));
        param.put("phoneNo", userInfo.getString("phoneNo"));
        param.put("bankCard", userInfo.getString("bankCard"));

        param.put("productCode", req.getProductCode());
        param.put("loanAmount", ruleNode.getCreditLimit());

        param.put("userId", userInfo.getString("userId"));
        param.put("sessionId", req.getSessionId());

        String jsonStr = param.toJSONString();

        try {
            log.info("请求fund接口url={},data={}", url, jsonStr);
            String tmp = HttpUtil.post(url, jsonStr);
            log.info("请求fund,result={}", tmp);
            Result<Map<String, String>> result = JSON.parseObject(tmp, Result.class);
            if (ErrMsgEnum.SUCCESS.getCode().equals(result.getCode())) {
                res = 1;
                log.info("请求fund申请成功");
            } else {
                log.info("请求fund申请失败");
            }
        } catch (Exception e) {
            log.error("请求fund接口异常url={},reqData={}", url, jsonStr, e);
        }
        return res;
    }

    //通知 催收催收 生成还款记录
    private Integer reqeustCollection(PreRequest req, RuleNode ruleNode) {
        int res = 0;
        Map<String, String> reData = new HashMap<>();
        String url = collectionRootUrl + "/event/saveResult";

        JSONObject param = new JSONObject();
        param.put("sessionId", req.getSessionId());
        param.put("productCode", req.getProductCode());
        param.put("eventType", req.getEventType());
        param.put("creditLimit", ruleNode.getCreditLimit());
        param.put("resultType", ruleNode.getResultType());
        String jsonStr = param.toJSONString();

        try {
            log.info("请求collection接口url={},data={}", url, jsonStr);
            String tmp = HttpUtil.post(url, jsonStr);
            log.info("请求collection,result={}", tmp);
            Result<Map<String, String>> result = JSON.parseObject(tmp, Result.class);
            if (ErrMsgEnum.SUCCESS.getCode().equals(result.getCode())) {
                res = 1;
            }
        } catch (Exception e) {
            log.error("请求collection接口异常url={},reqData={}", url, jsonStr, e);
        }
        return res;
    }

    /**
     * 请求本地变量
     *
     * @param req
     * @param intIds
     * @return
     */
    private Map<String, String> reqeustLocal(PreRequest req, String intIds, Integer cycleNum) {
        String res = "-1";
        Map<String, String> reData = new HashMap<>();
        String url = localRootUrl + "/local";

        LocalRequest reqObj = new LocalRequest();
        reqObj.setSessionId(req.getSessionId());
        reqObj.setTransTime(req.getTransTime());
        reqObj.setProductCode(req.getProductCode());
        reqObj.setCycleNum(cycleNum);

        String strData = JSON.toJSONString(req.getData());
        BaseCustomerInfo base = JSON.parseObject(strData, BaseCustomerInfo.class);
        reqObj.setName(base.getName());
        reqObj.setPhoneNo(base.getPhoneNo());
        reqObj.setIdCard(base.getIdCard());
        reqObj.setBankCard(base.getBankCard());
        reqObj.setExtendInfoMap(JSON.parseObject(strData, Map.class));

        List<String> varList = iProductVariateService.getLocalVar(req.getProductCode(), req.getEventType());
        reqObj.setFieldList(varList);

        String jsonStr = JSON.toJSONString(reqObj);
        try {
            String tmp = HttpUtil.post(url, jsonStr);
            Result<Map<String, String>> result = JSON.parseObject(tmp, Result.class);
            if (ErrMsgEnum.SUCCESS.getCode().equals(result.getCode())) {
                res = JSON.toJSONString(result.getData());
            }
        } catch (Exception e) {
            log.error("请求local接口异常url={},reqData={}", url, jsonStr, e);
        }

        //把数据组装为三方的标准结构
        reData.put(intIds, res);
        return reData;
    }

    /**
     * 请求三方变量
     *
     * @param req
     * @param intIds
     * @return
     */
    private Map<String, String> reqeustThird(PreRequest req, String intIds, Integer cycleNum) {
        Map<String, String> reData = new HashMap<>();
        String url = thirdRootUrl + "/info";

        ThirdRequest reqObj = new ThirdRequest();
        reqObj.setSessionId(req.getSessionId());
        reqObj.setTransTime(req.getTransTime());
        reqObj.setProductCode(req.getProductCode());
        reqObj.setCycleNum(cycleNum);
        reqObj.setIntIds(intIds);

        String strData = JSON.toJSONString(req.getData());
        BaseCustomerInfo base = JSON.parseObject(strData, BaseCustomerInfo.class);
        reqObj.setName(base.getName());
        reqObj.setPhoneNo(base.getPhoneNo());
        reqObj.setIdCard(base.getIdCard());
        reqObj.setBankCard(base.getBankCard());
        reqObj.setExtendInfoMap(JSON.parseObject(strData, Map.class));

        String jsonStr = JSON.toJSONString(reqObj);
        try {
            String tmp = HttpUtil.post(url, jsonStr);
            Result<Map<String, String>> result = JSON.parseObject(tmp, Result.class);
            if (ErrMsgEnum.SUCCESS.getCode().equals(result.getCode())) {
                reData = result.getData();
            }
        } catch (Exception e) {
            log.error("请求三方接口异常url={},reqData={}", url, jsonStr, e);
        }

        return reData;
    }


    /**
     * 请求决策引擎
     *
     * @param req
     * @param varMap
     * @return
     */
    private RuleNode reqeustRule(PreRequest req, Map<String, Object> varMap, Integer cycleNum) {
        RuleNode reData = null;
        String url = ruleRootUrl + "/execute";

        RuleRequest reqObj = new RuleRequest();
        reqObj.setOrderId(req.getSessionId());
        reqObj.setTransTime(req.getTransTime());
        reqObj.setProjectCode(req.getProductCode());
        reqObj.setEventCode(req.getEventType());
        reqObj.setCycleNum(cycleNum);
        reqObj.setData(varMap);//所有变量

        String jsonStr = JSON.toJSONString(reqObj);
        try {
            String tmp = HttpUtil.post(url, jsonStr);
            Result<RuleNode> result = JSON.parseObject(tmp, new TypeReference<Result<RuleNode>>() {
            });
            if (ErrMsgEnum.SUCCESS.getCode().equals(result.getCode())) {
                reData = result.getData();
            }
        } catch (Exception e) {
            log.error("请求决策引擎接口异常url={},reqData={}", url, jsonStr, e);
        }

        return reData;
    }
}
